package com.source.lightfowl.syslog.aspect;

import com.source.lightfowl.constant.SessionKey;
import com.source.lightfowl.person.entity.Person;
import com.source.lightfowl.person.entity.Url;
import com.source.lightfowl.person.entity.UsersExtends;
import com.source.lightfowl.syslog.annotation.LogAnnotation;
import com.source.lightfowl.syslog.pojo.Operation;
import com.source.lightfowl.syslog.service.OperationService;
import com.source.lightfowl.utils.IdWorker;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.util.Date;
import java.util.List;

/** 系统日志：切面处理类 */
@Aspect
@Component
public class SysLogAspect {

    private static final Logger log = LoggerFactory.getLogger(SysLogAspect.class);

    @Autowired
    private OperationService operationService;

    @Autowired
    private IdWorker idWorker;

    //定义切点 @Pointcut
    //在注解的位置切入代码
    @Pointcut("@annotation( com.source.lightfowl.syslog.annotation.LogAnnotation)")
    public void logPoinCut() {
    }

    //切面 配置通知
    @After("logPoinCut()")         //AfterReturning
    public void saveOperation(JoinPoint joinPoint) {
        log.info("---------------接口日志记录---------------");
        //保存日志
        Operation operation = new Operation();
        operation.setId(idWorker.nextId()+"");

        //从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //获取切入点所在的方法
        Method method = signature.getMethod();

        //获取操作--方法上的ViLog的值
        LogAnnotation viLog = method.getAnnotation(LogAnnotation.class);
        if (viLog != null) {
            //保存操作事件
            String operEvent = viLog.operEvent();
            operation.setOperEvent(operEvent);
            //保存日志类型
            int operType = viLog.operType();
            operation.setOperType(operType);
            log.info("operEvent="+operEvent+",operType="+operType);
        }

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        // 请求方式：POST/GET/other
        String httpMethod = request.getMethod();
        operation.setReqType(httpMethod);
        log.info("请求方式："+httpMethod);

        //操作的url
        String requestURI = request.getRequestURI();
        String requestURL = request.getRequestURL().toString();
        operation.setOperUrl(requestURL);
        log.info("请求URL："+requestURI);

        // 客户端ip
        String ip = request.getRemoteAddr();
        operation.setClientIp(ip);
        log.info("客户端ip地址："+ip);
        // 操作人账号、姓名
        Person user = (Person) request.getSession().getAttribute(SessionKey.USER);
        if(user != null) {
            String username = user.getLoginName();
            String id = user.getId();
            operation.setUserId(id);
            operation.setUserName(username);
        }else {
            operation.setUserName("未登录");
            operation.setUserId("未登陆");
        }
        log.info("用户id："+operation.getUserId()+",用户名："+operation.getUserName());

        //获取请求的类名
        String className = joinPoint.getTarget().getClass().getName();
        //获取请求的方法名
        String methodName = method.getName();
        operation.setDetails("访问类名：【"+className + "】。访问方法名：【" + methodName+"】");
        log.info("操作细节：访问类名：【"+ className+ "】。访问方法名：【" + methodName+"】");

        //操作时间
        operation.setOperTime(new Date());
        log.info("操作时间"+operation.getOperTime());
        //调用service保存Operation实体类到数据库
        operationService.save(operation);
    }


}